import measurementEnum from "../enum/measurement.enum"
import measuringPhaseEnum from "../enum/measuringPhase.enum"
import { InvalidFloorException } from "../exception/floor.exception"
import Grouper from "../utils/Grouper"
import Logger from "../utils/Logger"
import * as THREE from "three"
import SnappablePointer from "./SnappablePointer"
import MeasurementModeModule from "../module/MeasurementModeModule"
import ViewmodeData from "../data/ViewmodeData"
import FloorsViewData from "../data/FloorsViewData"
import { InputSubscription } from "../module/InputIniModule"
import ConstrainedHit from "../utils/ConstrainedHit"
export default class MeasurementCreator {
  points: Grouper
  setSelected: MeasurementModeModule["setSelected"]
  pointer: SnappablePointer
  changePhase: MeasurementModeModule["changePhase"]
  getPhase: MeasurementModeModule["getPhase"]
  isFloorplan: ViewmodeData["isFloorplan"]
  currentFloorId: FloorsViewData["getHighestVisibleFloorId"]
  currentRoomId: FloorsViewData["getHighestVisibleFloorId"]
  inferRoomAssociation: any
  id: typeof MeasurementCreator
  onGroupCreated: MeasurementModeModule["onCreatorAddNewLine"]
  onGroupAddPoint: MeasurementModeModule["onCreatorAddPoint"]
  onDone: MeasurementModeModule["onCreatorStop"]
  onEdit: MeasurementModeModule["onEdit"]
  previousPhase: number
  currentLinePoints: number
  previousPoint: THREE.Vector3
  inputSubscriptions: InputSubscription[]
  log: Logger
  createNewLine: (e: ConstrainedHit) => void
  currentGroup: number
  addPointToLine: (e: ConstrainedHit) => void
  updateLastPoint: (e: ConstrainedHit) => void
  getIntersection: (e?: any) => ConstrainedHit
  setPhase: (e: number) => void
  restorePreviousPhase: () => void
  constructor(e, t, i, s, n, r, o, a, h) {
    this.points = e
    this.setSelected = t
    this.pointer = i
    this.changePhase = s
    this.getPhase = n
    this.isFloorplan = r
    this.currentFloorId = o
    this.currentRoomId = a
    this.inferRoomAssociation = h
    this.id = MeasurementCreator
    this.onGroupCreated = () => null
    this.onGroupAddPoint = () => null
    this.onDone = () => null
    this.onEdit = () => null
    this.previousPhase = measuringPhaseEnum.IDLE
    this.currentLinePoints = 0
    this.previousPoint = new THREE.Vector3()
    this.inputSubscriptions = []
    this.log = new Logger("measurement-creator")
    this.createNewLine = e => {
      const t = this.inferRoomAssociation(e.point)
      const i = e.roomId || t.roomId || this.currentRoomId() || null
      const s = e.floorId || t.floorId || this.currentFloorId()
      if ((this.log.debug(`Starting measurement: floorId="${s}" roomId="${i}"`), !s))
        throw new InvalidFloorException(`Cannot create new line on invalid floor '${s}'`)
      const n = {
        visible: !0,
        roomId: i,
        floorId: s,
        type: this.isFloorplan() ? measurementEnum.FloorplanOnly : measurementEnum.ThreeD,
        text: "",
        created: new Date(),
        modified: new Date()
      }
      const r = this.points.startGroup(n)
      this.currentGroup = r
      this.points.push(e.point)
      this.currentLinePoints = 1
      this.setSelected(r)
      const o = this.points.getGroup(r)
      this.onGroupCreated(o.info.sid)
      this.pointer.setOrigin(e, !0)
    }
    this.addPointToLine = e => {
      this.previousPoint = this.previousPoint.copy(e.point)
      this.points.push(e.point)
      ++this.currentLinePoints
      this.onGroupAddPoint()
      this.pointer.setOrigin(e, !0)
    }
    this.updateLastPoint = e => {
      this.points.update(this.points.length - 1, e.point)
    }
    this.getIntersection = e => this.pointer.getIntersection(e)
    this.setPhase = e => {
      const t = this.getPhase()
      e !== t && ((this.previousPhase = t), this.changePhase(e))
    }
    this.restorePreviousPhase = () => {
      this.setPhase(this.previousPhase)
    }
  }
  start() {
    if (this.getPhase() === measuringPhaseEnum.IDLE) {
      this.previousPoint.set(1000, 1000, 1000)
      this.setPhase(measuringPhaseEnum.CREATING)
      this.setSelected(-1)
      for (const e of this.inputSubscriptions) e.renew()
    }
  }
  cancelSubs() {
    for (const e of this.inputSubscriptions) e.cancel()
  }
  stop() {
    this.cancelSubs()
    this.currentLinePoints = 0
    this.setSelected(-1)
    this.setPhase(measuringPhaseEnum.IDLE)
    this.pointer.clearOrigin()
    this.onDone()
  }
}
